import _ from 'lodash';
import events  from 'events';
import {actions, actionNames} from './action';
const EventEmitter = events.EventEmitter;

let serverUrl = 'ws://127.0.0.1:5543';

let serverUrlChanged = true;

const options = {
    maxAttemptedTimes: 0,
    reconnectDelay: 2000//最小500ms
};

let wsIndex = 0;
let attemptedTimes = 0;
let stopped = true;

function WebSocketWrapper(id, url) {
    this.id = id;
    this._url = url;
    this._closing = false;
}
WebSocketWrapper.prototype.id = '';
WebSocketWrapper.prototype._url = 'ws://127.0.0.1';
WebSocketWrapper.prototype._ws = null;
WebSocketWrapper.prototype._closing = false;
WebSocketWrapper.prototype.connect = function () {
    if (!this._closing && !this._ws) {
        const ws = this._ws = new WebSocket(this._url);
        ws.onmessage = (event) => {
            if (this.onmessage) {
                this.onmessage(event);
            }
        };
        ws.onclose = () => {
            if (this.onclose) {
                this.onclose();
            }
        };
        ws.onopen = () => {
            if (this.onopen) {
                this.onopen();
            }
        };
    }
};
WebSocketWrapper.prototype.close = function () {
    this._closing = true;
    if (this._ws) {
        this._ws.close();
        this._ws = null;
    }
};
WebSocketWrapper.prototype.send = function (msg) {
    if (!this._closing && this._ws && this._ws.readyState === 1) {
        this._ws.send(msg);
    } else {
        return false;
    }
};
WebSocketWrapper.prototype.connected = function () {
    return this._ws.readyState === 1;
};

const wsSocks = {};

const RTServer = new EventEmitter();
const reSubscribe = function () {
};
RTServer.on('removeListener', reSubscribe);
RTServer.on('newListener', reSubscribe);
_.extend(RTServer, {
    actions,
    setServerUrl: function (url) {
        if (url !== serverUrl) {
            serverUrlChanged = true;
        }
        serverUrl = url;
    },
    getServerUrl: function () {
        return serverUrl;
    },
    getOptions: function () {
        return _.clone(options);
    },
    setOptions: function (options) {
        _.extend(options, {
            maxAttemptedTimes: options.maxAttemptedTimes >= 0 ? options.maxAttemptedTimes : 0,
            reconnectDelay: options.reconnectDelay >= 500 ? options.reconnectDelay : 500
        });
    },
    isRunning: function () {
        return !stopped;
    },
    connect: function () {
        attemptedTimes = 0;
        if (!serverUrlChanged && !stopped) {
            return;
        }
        stopped = false;
        _.each(wsSocks, function (ws) {
            ws.initiativedClosing = true;
            ws.close();
        });
        wsIndex += 1;
        const id = String(wsIndex);
        const ws = wsSocks[id] = new WebSocketWrapper(id, serverUrl);
        ws.onmessage = (event) => {
            try {
                const data = event.data;
                let msg = JSON.parse(data);
                if (msg.action in actionNames) {
                    this.emit(actionNames[msg.action], msg.data);
                }
            } catch (err) {
                console.error(err);
            }
        };
        ws.onclose = () => {
            delete wsSocks[ws.id];
            if (!ws.initiativedClosing) {
                attemptedTimes++;
                if (options.maxAttemptedTimes > 0 && attemptedTimes >= options.maxAttemptedTimes) {
                    attemptedTimes = 0;
                    stopped = true;
                    this.emit('error');
                } else {
                    wsIndex += 1;
                    const id = String(wsIndex);
                    const ws = wsSocks[id] = new WebSocketWrapper(id, serverUrl);
                    setTimeout(() => {
                        ws.connect();
                    }, options.reconnectDelay);
                }
            }
        };
        ws.onopen = () => {
            attemptedTimes = 0;
            reSubscribe();
            this.emit('open');
        };
        ws.connect();
    },
    send: function (msg) {
        const message = JSON.stringify(msg);
        _.each(wsSocks, function (ws) {
            ws.send(message);
        });
    }
});

export default RTServer;
